package com.acme.bankapp.service.bank;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.ParseException;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.acme.bankapp.domain.bank.account.Account;
import com.acme.bankapp.domain.bank.account.CheckingAccount;
import com.acme.bankapp.domain.bank.account.SavingsAccount;
import com.acme.bankapp.domain.bank.client.Client;
import com.acme.bankapp.domain.bank.client.Gender;
import com.acme.bankapp.service.bank.exception.ClientExistsException;

public class BankDataLoaderService {

	private static final String regexClient = "name=(\\w[ \\w]*);gender=(m|f);";

	private static final int GENDER_GROUP = 2;

	private static final String GENDER_MALE = "m";

	private static final String GENDER_FEMALE = "f";

	private static final int NAME_GROUP = 1;

	private static final String regexAccount = "accounttype=(((c);balance=([0-9]*\\.?[0-9]+);overdraft=([0-9]*\\.?[0-9]+))|((s);balance=([0-9]*\\.?[0-9]+)));";

	private static final String SAVINGS_ACCOUNT = "s";

	private static final int SAVINGS_GROUP = 7;

	private static final int SAVINGS_BALANCE_GROUP = 8;

	private static final String CHECKING_ACCOUNT = "c";

	private static final int CHECKING_GROUP  = 3;

	private static final int CHECKING_BALANCE_GROUP = 4;

	private static final int CHECKING_OVERDRAFT_GROUP = 5;

	private static void parseAccounts(Client client, String line) throws ParseException, NumberFormatException {
		Pattern pattern = Pattern.compile(regexAccount);
		Matcher matcher = pattern.matcher(line);
		while (matcher.find()) {
			if (SAVINGS_ACCOUNT.equals(matcher.group(SAVINGS_GROUP))) {
				double balance = Double.parseDouble(matcher.group(SAVINGS_BALANCE_GROUP));
				try {
					client.addAccount(new SavingsAccount(balance));
				} catch (IllegalArgumentException exception) {
					continue;
				} catch (ArrayIndexOutOfBoundsException exception) {
					continue;
				}
			} else if (CHECKING_ACCOUNT.equals(matcher.group(CHECKING_GROUP))) {
				double balance = Double.parseDouble(matcher.group(CHECKING_BALANCE_GROUP));
				double overdraft = Double.parseDouble(matcher.group(CHECKING_OVERDRAFT_GROUP));
				try {
					client.addAccount(new CheckingAccount(balance, overdraft));
				} catch (IllegalArgumentException exception) {
					continue;
				} catch (ArrayIndexOutOfBoundsException exception) {
					continue;
				}
			} else {
				throw new ParseException(line, 0);
			}
		}
	}

	public static Client parseClient(String line) throws ParseException, NumberFormatException {
		Pattern pattern = Pattern.compile(regexClient);
		Matcher matcher = pattern.matcher(line);
		if (matcher.find()) {
			Gender gender = null;
			if (GENDER_MALE.equals(matcher.group(GENDER_GROUP))) {
				gender = Gender.MALE;
			} else if (GENDER_FEMALE.equals(matcher.group(GENDER_GROUP))) {
				gender = Gender.FEMALE;
			} else {
				throw new ParseException(line, GENDER_GROUP);
			}
			String name = matcher.group(NAME_GROUP);

			Client client = new Client(name, gender);
			parseAccounts(client, line);
			return client;
		}
		else {
			throw new ParseException(line, 0);
		}
	}

	public static void readFeed(Bank bank, String fileName) throws ParseException, NumberFormatException {
		FileReader file = null;
		BufferedReader reader = null;
		try {
			file = new FileReader(fileName);
			reader = new BufferedReader(file);

			String line = null;
			while ((line = reader.readLine()) != null) {
				Client client = parseClient(line);
				try {
					bank.addClient(client);
				} catch (ArrayIndexOutOfBoundsException exception) {
					continue;
				} catch (ClientExistsException exception) {
					continue;
				}
			}
		} catch (IOException exception) {
			System.out.println("Error IO with feed file");
		} finally {
			if (file != null) {
				try {
					file.close();
				} catch (IOException e) {}
			}
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {}
			}
		}
	}
}
